import { Router } from 'express';
import { Prisma } from '@prisma/client';
import Paths from '@src/common/constants/Paths';
import { prisma } from '@src/common/database';
import { jsonResponse } from '@src/common/util/bigint-serializer';
import DatabaseUtils from '@src/common/db-utils';

const SESSION_COOKIE = 'sid';

async function getCurrentUser(req: any) {
  try {
    const sid = req.cookies?.[SESSION_COOKIE];
    if (!sid) return null;
    const sess = await prisma.userSession.findUnique({ where: { id: BigInt(sid) } });
    if (!sess || new Date(sess.expiredAt) < new Date()) return null;
    const user = await prisma.user.findUnique({ where: { id: sess.userId } });
    return user;
  } catch {
    return null;
  }
}



const router = Router();

// 은행 계좌 관리 (간단한 CRUD)
router.get(Paths.Admin.BankAccounts, async (_req, res) => {
  try {
    const list = await prisma.bankAccount.findMany({ orderBy: { createdAt: 'desc' } });
    return jsonResponse(res, list);
  } catch (err) {
    console.error('은행 계좌 목록 조회 실패:', err);
    return res.status(500).json({ error: '은행 계좌 목록을 가져오는데 실패했습니다' });
  }
});

router.post(Paths.Admin.BankAccounts, async (req, res) => {
  try {
    const { displayName, bankName, accountName, accountNumber, note, qrCodeUrl, isActive = true } = req.body ?? {};
    const disp = displayName || bankName || accountName;
    if (!disp) {
      return res.status(400).json({ error: 'displayName 또는 bankName/accountName 중 하나는 필수입니다' });
    }
    const created = await prisma.bankAccount.create({
      data: {
        displayName: String(disp),
        bankName: bankName || null,
        accountName: accountName || null,
        accountNumber: accountNumber || null,
        note: note || null,
        qrCodeUrl: qrCodeUrl || null,
        isActive: !!isActive,
      },
    });
    return jsonResponse(res, created);
  } catch (err) {
    console.error('은행 계좌 생성 실패:', err);
    return res.status(500).json({ error: '은행 계좌 생성에 실패했습니다' });
  }
});

router.put(Paths.Admin.BankAccounts + '/:id', async (req, res) => {
  try {
    const { id } = req.params as any;
    const data: any = {};
    ['displayName','bankName','accountName','accountNumber','note','qrCodeUrl','isActive'].forEach(k=>{
      if (k in req.body) (data as any)[k] = req.body[k];
    })
    const updated = await prisma.bankAccount.update({ where: { id: BigInt(id) }, data });
    return jsonResponse(res, updated);
  } catch (err) {
    console.error('은행 계좌 수정 실패:', err);
    return res.status(500).json({ error: '은행 계좌 수정에 실패했습니다' });
  }
});

router.delete(Paths.Admin.BankAccounts + '/:id', async (req, res) => {
  try {
    const { id } = req.params as any;
    await prisma.bankAccount.delete({ where: { id: BigInt(id) } });
    return res.json({ success: true });
  } catch (err) {
    console.error('은행 계좌 삭제 실패:', err);
    return res.status(500).json({ error: '은행 계좌 삭제에 실패했습니다' });
  }
});

// 충전 심사
router.get(Paths.Admin.Recharges, async (req, res) => {
  try {
    const { status, userId } = req.query as any;
    const where: any = {};
    if (status) where.status = String(status);
    if (userId) where.userId = BigInt(userId);

    const list = await prisma.recharge.findMany({
      where,
      orderBy: { createdAt: 'desc' },
      include: {
        user: {
          select: {
            id: true,
            loginId: true,
            name: true,
            nickname: true,
            email: true
          }
        }
      }
    });
    return jsonResponse(res, list);
  } catch (err) {
    console.error('충전 주문 목록 조회 실패:', err);
    return res.status(500).json({ error: '충전 주문 목록을 가져오는데 실패했습니다' });
  }
});

router.put(Paths.Admin.Recharges + '/:id/approve', async (req, res) => {
  try {
    const { id } = req.params as any;

    const result = await prisma.$transaction(async (tx) => {
      const rec = await tx.recharge.findUnique({ where: { id: BigInt(id) } });
      if (!rec) throw new Error('충전 신청이 존재하지 않습니다');
      if (rec.status !== 'pending') throw new Error('충전 신청 상태가 비정상입니다');

      const updated = await tx.recharge.update({
        where: { id: rec.id },
        data: { status: 'approved', reviewedAt: new Date() },
      });

      // 공통 유틸리티를 사용하여 잔액 증가 및 장부 기록
      await DatabaseUtils.updateWalletBalance(rec.userId, rec.pointsCredited, 'recharge', 'recharge', rec.id);

      return updated;
    });

    return jsonResponse(res, result);
  } catch (err: any) {
    console.error('승인 처리 실패:', err);
    return res.status(400).json({ error: err.message || '승인 처리에 실패했습니다' });
  }
});

router.put(Paths.Admin.Recharges + '/:id/reject', async (req, res) => {
  try {
    const { id } = req.params as any;
    const updated = await prisma.recharge.update({ where: { id: BigInt(id) }, data: { status: 'rejected', reviewedAt: new Date() } });
    return jsonResponse(res, updated);
  } catch (err) {
    console.error('심사 거부 실패:', err);
    return res.status(500).json({ error: '심사 거부에 실패했습니다' });
  }
});

// ========== 출금 심사 ==========
router.get(Paths.Admin.Withdrawals, async (req, res) => {
  try {
    const { status, userId } = req.query as any
    const where: any = {}
    if (status) where.status = String(status)
    if (userId) where.userId = BigInt(userId)
    const list = await prisma.withdrawal.findMany({ 
      where, 
      orderBy: { createdAt: 'desc' },
      include: {
        user: {
          select: {
            id: true,
            loginId: true,
            name: true,
            nickname: true,
            email: true
          }
        }
      }
    })
    return jsonResponse(res, list)
  } catch (err) {
    console.error('출금 목록 조회 실패:', err)
    return res.status(500).json({ error: '출금 목록을 가져오는데 실패했습니다' })
  }
})

router.put(Paths.Admin.Withdrawals + '/:id/approve', async (req, res) => {
  try {
    const { id } = req.params as any
    const result = await prisma.$transaction(async (tx) => {
      const w = await tx.withdrawal.findUnique({ where: { id: BigInt(id) } })
      if (!w) throw new Error('출금 신청이 존재하지 않습니다')
      if (w.status !== 'pending') throw new Error('출금 신청 상태가 비정상입니다')

      // 승인 전 잔액 확인
      const wallet = await tx.userWallet.findUnique({ where: { userId: w.userId } })
      const bal = wallet?.pointsBalance || BigInt(0)
      if (bal < w.pointsToWithdraw) throw new Error('사용자 포인트가 부족하여 차감할 수 없습니다')

      const updated = await tx.withdrawal.update({ where: { id: w.id }, data: { status: 'approved', reviewedAt: new Date() } })
      await tx.userWallet.update({ where: { userId: w.userId }, data: { pointsBalance: { decrement: w.pointsToWithdraw } } })
      await tx.pointLedger.create({ data: { userId: w.userId, deltaPoints: -w.pointsToWithdraw, reason: 'withdraw', relatedType: 'withdraw', relatedId: w.id, note: '출금 차감' } })
      return updated
    })
    return jsonResponse(res, result)
  } catch (err: any) {
    console.error('출금 승인 실패:', err)
    return res.status(400).json({ error: err.message || '출금 승인에 실패했습니다' })
  }
})

router.put(Paths.Admin.Withdrawals + '/:id/reject', async (req, res) => {
  try {
    const { id } = req.params as any
    const { remark } = req.body ?? {}
    const updated = await prisma.withdrawal.update({ where: { id: BigInt(id) }, data: { status: 'rejected', reviewedAt: new Date(), remark: remark || undefined } })
    return jsonResponse(res, updated)
  } catch (err) {
    console.error('출금 거부 실패:', err)
    return res.status(500).json({ error: '출금 거부에 실패했습니다' })
  }
})

// 출금 신청 은행 정보 수정
router.put(Paths.Admin.Withdrawals + '/:id/bank-info', async (req, res) => {
  try {
    const { id } = req.params as any
    const { bankName, accountName, accountNumber, accountId } = req.body ?? {}

    // 은행 정보 검증
    if (!bankName || !accountName || !accountNumber || !accountId) {
      return res.status(400).json({ error: '은행명, 예금주명, 계좌번호, 신분증번호는 필수 입력사항입니다' })
    }

    const updated = await prisma.withdrawal.update({
      where: { id: BigInt(id) },
      data: {
        payoutBankName: String(bankName).trim(),
        payoutAccountName: String(accountName).trim(),
        payoutAccountNumber: String(accountNumber).trim(),
        payoutAccountId: String(accountId).trim(),
      }
    })
    return jsonResponse(res, updated)
  } catch (err) {
    console.error('출금 은행 정보 수정 실패:', err)
    return res.status(500).json({ error: '출금 은행 정보 수정에 실패했습니다' })
  }
})

// 선물 관리
router.get(Paths.Admin.Gifts, async (_req, res) => {
  try {
    const list = await prisma.gift.findMany({ orderBy: { createdAt: 'desc' } });
    return jsonResponse(res, list);
  } catch (err) {
    console.error('선물 목록 조회 실패:', err);
    return res.status(500).json({ error: '선물 목록을 가져오는데 실패했습니다' });
  }
});

router.post(Paths.Admin.Gifts, async (req, res) => {
  try {
    const { name, iconUrl, pricePoints, isActive = true, effectPreset, effectOptions } = req.body ?? {};
    if (!name || !pricePoints) {
      return res.status(400).json({ error: 'name과 pricePoints는 필수 입력사항입니다' });
    }
    const created = await prisma.gift.create({
      data: {
        name: String(name),
        iconUrl: iconUrl || null,
        pricePoints: BigInt(pricePoints),
        isActive: !!isActive,
        effectPreset: effectPreset ? String(effectPreset) : null,
        effectOptions: effectOptions ?? null,
      },
    });
    return jsonResponse(res, created);
  } catch (err) {
    console.error('선물 생성 실패:', err);
    return res.status(500).json({ error: '선물 생성에 실패했습니다' });
  }
});

router.put(Paths.Admin.Gifts + '/:id', async (req, res) => {
  try {
    const { id } = req.params as any;
    const data: any = {};
    ['name','iconUrl','pricePoints','isActive','effectPreset','effectOptions'].forEach(k=>{
      if (k in req.body) {
        if (k === 'pricePoints') data[k] = BigInt(req.body[k]);
        else if (k === 'effectPreset') data[k] = req.body[k] ? String(req.body[k]) : null;
        else data[k] = req.body[k];
      }
    })
    const updated = await prisma.gift.update({ where: { id: BigInt(id) }, data });
    return jsonResponse(res, updated);
  } catch (err) {
    console.error('선물 수정 실패:', err);
    return res.status(500).json({ error: '선물 수정에 실패했습니다' });
  }
});

router.delete(Paths.Admin.Gifts + '/:id', async (req, res) => {
  try {
    const { id } = req.params as any;
    await prisma.gift.delete({ where: { id: BigInt(id) } });
    return res.json({ success: true });
  } catch (err) {
    console.error('선물 삭제 실패:', err);
    return res.status(500).json({ error: '선물 삭제에 실패했습니다' });
  }
});

// 선물 발송 기록
router.get('/gift-sends', async (req, res) => {
  try {
    const { liveRoomId, userId, giftId } = req.query as any;
    const where: any = {};
    if (liveRoomId) where.liveRoomId = BigInt(liveRoomId);
    if (userId) where.senderUserId = BigInt(userId);
    if (giftId) where.giftId = BigInt(giftId);

    const list = await prisma.giftSend.findMany({
      where,
      include: {
        gift: true,
        sender: { select: { id: true, loginId: true } },
        liveRoom: { select: { id: true, title: true } }
      },
      orderBy: { createdAt: 'desc' },
      take: 100
    });
    return jsonResponse(res, list);
  } catch (err) {
    console.error('선물 발송 기록 조회 실패:', err);
    return res.status(500).json({ error: '선물 발송 기록을 가져오는데 실패했습니다' });
  }
});

// 관리자 선물 발송 기록 조회
router.get('/admin-gift-sends', async (req, res) => {
  try {
    const user = await getCurrentUser(req);
    if (!user) return res.status(401).json({ error: '로그인되지 않음' });

    const { limit = 50 } = req.query as any;
    const l = Math.min(Math.max(Number(limit) || 50, 1), 100);

    // 직播间礼物发送记录
    const liveGiftSends = await prisma.giftSend.findMany({
      where: { senderUserId: user.id },
      include: {
        gift: { select: { id: true, name: true, iconUrl: true } },
        liveRoom: { select: { id: true, title: true } },
        channel: { select: { id: true, name: true } }
      },
      orderBy: { createdAt: 'desc' },
      take: Math.floor(l / 2)
    });

    // 聊天室礼物发送记录
    const chatGiftSends = await prisma.chatGiftSend.findMany({
      where: { senderUserId: user.id },
      include: {
        gift: { select: { id: true, name: true, iconUrl: true } },
        room: { select: { id: true, title: true } },
        receiver: { select: { id: true, nickname: true, name: true } }
      },
      orderBy: { createdAt: 'desc' },
      take: Math.floor(l / 2)
    });

    // 合并并格式化记录
    const records = [
      ...liveGiftSends.map(record => ({
        id: `live_${record.id}`,
        type: 'live',
        giftName: record.gift.name,
        giftIcon: record.gift.iconUrl,
        roomName: record.liveRoom?.title || record.channel?.name || `라이브 방${record.liveRoomId}`,
        quantity: record.quantity,
        totalPoints: Number(record.totalPoints),
        createdAt: record.createdAt,
        receiverName: null
      })),
      ...chatGiftSends.map(record => ({
        id: `chat_${record.id}`,
        type: 'chat',
        giftName: record.gift.name,
        giftIcon: record.gift.iconUrl,
        roomName: record.room?.title || `채팅방${record.chatRoomId}`,
        quantity: record.quantity,
        totalPoints: Number(record.totalPoints),
        createdAt: record.createdAt,
        receiverName: record.receiver?.nickname || record.receiver?.name || `사용자${record.receiverUserId}`
      }))
    ];

    // 按时间排序
    records.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());

    return jsonResponse(res, records.slice(0, l));
  } catch (err) {
    console.error('관리자 선물 발송 기록 조회 실패:', err);
    return res.status(500).json({ error: '선물 발송 기록을 가져오는데 실패했습니다' });
  }
});

// 포인트 상품 패키지 관리
router.get(Paths.Admin.PointPackages, async (_req, res) => {
  try {
    const list = await prisma.pointPackage.findMany({
      orderBy: [{ sortOrder: 'asc' }, { createdAt: 'desc' }]
    });
    return jsonResponse(res, list);
  } catch (err) {
    console.error('포인트 상품 패키지 목록 조회 실패:', err);
    return res.status(500).json({ error: '포인트 상품 패키지 목록을 가져오는데 실패했습니다' });
  }
});

router.post(Paths.Admin.PointPackages, async (req, res) => {
  try {
    const {
      name,
      description,
      pointsAmount,
      priceDecimal,
      imageUrl,
      badge,
      sortOrder = 0,
      isActive = true,
      isRecommended = false
    } = req.body ?? {};

    if (!name || !pointsAmount || !priceDecimal) {
      return res.status(400).json({ error: '이름, 포인트 금액, 가격은 필수 입력사항입니다' });
    }

    const created = await prisma.pointPackage.create({
      data: {
        name: String(name),
        description: description ? String(description) : null,
        pointsAmount: BigInt(pointsAmount),
        priceDecimal: new Prisma.Decimal(String(priceDecimal)),
        imageUrl: imageUrl ? String(imageUrl) : null,
        badge: badge ? String(badge) : null,
        sortOrder: Number(sortOrder),
        isActive: !!isActive,
        isRecommended: !!isRecommended,
      },
    });
    return jsonResponse(res, created);
  } catch (err) {
    console.error('포인트 상품 패키지 생성 실패:', err);
    return res.status(500).json({ error: '포인트 상품 패키지 생성에 실패했습니다' });
  }
});

router.put(Paths.Admin.PointPackages + '/:id', async (req, res) => {
  try {
    const { id } = req.params as any;
    const data: any = {};

    ['name', 'description', 'pointsAmount', 'priceDecimal', 'imageUrl', 'badge', 'sortOrder', 'isActive', 'isRecommended'].forEach(k => {
      if (k in req.body) {
        if (k === 'pointsAmount') {
          data[k] = BigInt(req.body[k]);
        } else if (k === 'priceDecimal') {
          data[k] = new Prisma.Decimal(String(req.body[k]));
        } else if (k === 'sortOrder') {
          data[k] = Number(req.body[k]);
        } else if (k === 'isActive' || k === 'isRecommended') {
          data[k] = !!req.body[k];
        } else if (k === 'description' || k === 'imageUrl' || k === 'badge') {
          data[k] = req.body[k] ? String(req.body[k]) : null;
        } else {
          data[k] = req.body[k];
        }
      }
    });

    const updated = await prisma.pointPackage.update({
      where: { id: BigInt(id) },
      data
    });
    return jsonResponse(res, updated);
  } catch (err) {
    console.error('포인트 상품 패키지 수정 실패:', err);
    return res.status(500).json({ error: '포인트 상품 패키지 수정에 실패했습니다' });
  }
});

router.delete(Paths.Admin.PointPackages + '/:id', async (req, res) => {
  try {
    const { id } = req.params as any;
    await prisma.pointPackage.delete({ where: { id: BigInt(id) } });
    return res.json({ success: true });
  } catch (err) {
    console.error('포인트 상품 패키지 삭제 실패:', err);
    return res.status(500).json({ error: '포인트 상품 패키지 삭제에 실패했습니다' });
  }
});

export default router;

